<?php
/**
 * Author:   tangxiaowen
 * Email:    846506584@qq.com
 * Date:     2019/6/10 0010
 * Describe: 富友支付类.
 */

namespace app\api\controller\fuyou;

use think\Log;
use think\Request;
use think\Controller;

class Fuyou extends Controller
{
    //商户代码||商户号(立时贷提供文档名称不统一 故两个名称)
    private static $merchantCode;
    //秘钥
    private static $secretKey;
    //基础公共参数
    private static $config = [
        'VERSION' => '2.3', //版本号
        'TYPE' => '03', //交易类型
        'BACKURL' => '', //后台通知地址
        'SIGNTP' => 'MD5', // sign 加密方式 md5||rsa
        'IDTYPE' => 0, //证件类型 0身份证
    ];

    //请求url
    private static $requestUrl = [
        'merchantOrder' => 'http://www-1.fuioupay.com:18670/mobile_pay/apipay/orderAction.pay', //3.1 商户下单、验证码获取接口
        'pay' => 'http://www-1.fuioupay.com:18670/mobile_pay/apipay/payAction.pay', //3.2 支付接口
        'messageAction' => '址：http://www-1.fuioupay.com:18670/mobile_pay/apipay/messageAction.pay', //3.3 重发验证码接口
    ];

    public function __construct()
    {
        //日志初始化保存地址
        $setPath = strtolower(request()->module().'/'.request()->controller().'/'.request()->action().'/');
        Log::init(['path' => LOG_PATH.$setPath, 'type' => 'file']);

        //初始化支付配置
        $this->initConfig();

        //配置富友回到地址
        $systemInfo = model('System')->getSystemInfo();
        self::$config['BACKURL'] = $systemInfo['SystemDomain'].'/api.php/fuyou/Callback/apyCallback';
    }

    /**
     * 3.1 商户下单、验证码获取接口
     * 接口说明：进行支付前，商户需先调用此接口。
     */
    public function merchantOrder()
    {
        echo 2;
        echo 3;
        echo 4;
        die;
        //验证参数
        $header = Request::instance()->header();
        $userId = $header['userid'] ?? '';
        if (!$userId) {
            returnErrorResult('缺少用户ID');
        }
        $postData = Request()->only('orderId');
        $result = $this->validate($postData, 'app\common\validate\fuyou\Fuyou.merchantOrder');
        if ($result !== true) {
            returnErrorResult($result);
        }

        //订单信息
        $orderInfo = model('Order')->getIdOrderInfo($postData['orderId']);
        //订单应还款额
        $orderModel = model('Order')->getOrderShould($orderInfo);
        //用户信息
        $userInfo = model('User')->getIdUserInfo($userId);
        //用户银行卡信息
        $userBankInfo = model('User')->getUserBank($userId);

        //设置加密签名
        $singTemp = [
            self::$config['TYPE'], //交易类型
            self::$config['VERSION'], //版本号
            self::$merchantCode, //商户代码
            $orderInfo['OrderSn'], //商户订单流水号商户确保唯一
            $userId, //商户端用户的唯一编号，即用户 ID
            ($orderModel * 100), //交易金额，分为单位
            $userBankInfo['BankNo'], //银行卡号
            self::$config['BACKURL'], //后台通知 URL
            $userInfo['TrueName'], //用户姓名
            $userInfo['IDCard'], //用户证件号，此处填写身份证号
            self::$config['IDTYPE'], //证件类型 0身份证
            $userBankInfo['YMobile'], //银行预留手机号
            request()->ip(), //客户所在 IP 地址
            self::$secretKey, //商户 32 位密钥 key
        ];
        $sign = md5(implode('|', $singTemp));

        $STR = '<REQUEST>
            <VERSION>'.self::$config['VERSION'].'</VERSION>
            <USERIP>'.request()->ip().'</USERIP>
            <MCHNTCD>'.self::$merchantCode.'</MCHNTCD>
            <TYPE>'.self::$config['TYPE'].'</TYPE>
            <MCHNTORDERID>'.$orderInfo['OrderSn'].'</MCHNTORDERID>
            <USERID>'.$userInfo['ID'].'</USERID>
            <AMT>'.($orderModel * 100).'</AMT>
            <BANKCARD>'.$userBankInfo['BankNo'].'</BANKCARD>
            <NAME>'.$userInfo['TrueName'].'</NAME>
            <IDTYPE>'.self::$config['IDTYPE'].'</IDTYPE>
            <IDNO>'.$userInfo['IDCard'].'</IDNO>
            <MOBILE>'.$userBankInfo['YMobile'].'</MOBILE>
            <BACKURL>'.self::$config['BACKURL'].'</BACKURL>
            <SIGNTP>'.self::$config['SIGNTP'].'</SIGNTP>
            <SIGN>'.$sign.'</SIGN>
        </REQUEST>';

        $APIFMS = CryptDes::encrypt_base64($STR, self::$secretKey);
        $param = [
            'MCHNTCD' => self::$merchantCode,
            'APIFMS' => $APIFMS,
        ];
        $result = $this->curlPost(self::$requestUrl['merchantOrder'], $param);
        $xml_result = CryptDes::decrypt_base64($result, self::$secretKey);
        $result = $this->xmlToArray($xml_result);
        if (isset($result['RESPONSECODE']) && $result['RESPONSECODE'] == '0000') {
            $this->resSuccess('下单成功', 000, $result);
        } else {
            Log::record('富友-商户下单-返回数据 解密前'.$xml_result);
            Log::record('富友-商户下单-返回数据 解密后 '.json_encode($result, JSON_UNESCAPED_UNICODE));
            $this->resError('下单失败');
        }
    }

    /**
     * 3.2 支付接口
     * 接口说明：用户填写验证码后调用此接口进行支付。
     */
    public function pay()
    {
        //验证参数
        $header = Request::instance()->header();
        $userId = $header['userid'] ?? '';
        if (!$userId) {
            returnErrorResult('缺少用户ID');
        }
        $postData = Request()->only('result,vsCode');
        $result = $this->validate($postData, 'app\common\validate\fuyou\Fuyou.pay');
        if ($result !== true) {
            returnErrorResult($result);
        }
        $fyParam = json_decode($postData['result'], true);
        if (!$fyParam) {
            returnErrorResult('系统错误，请稍后再试');
        }

        $userInfo = model('User')->getIdUserInfo($userId);
        $userBankInfo = model('User')->getUserBank($userId);

        //设置加密签名
        $singTemp = [
            self::$config['TYPE'], //交易类型
            self::$config['VERSION'], //版本号
            self::$merchantCode, //商户代码
            $fyParam['ORDERID'], //富友订单号
            $fyParam['MCHNTORDERID'], //商户订单号
            $fyParam['USERID'], //商户端用户的唯一编号，即用户 ID
            $userBankInfo['BankNo'], //银行卡号
            $postData['vsCode'], //短信验证码
            $userBankInfo['YMobile'], //银行预留手机号
            request()->ip(), //客户所在 IP 地址
            self::$secretKey, //商户 32 位密钥 key
        ];
        $sign = md5(implode('|', $singTemp));

        $STR = '<REQUEST>
            <VERSION>'.self::$config['VERSION'].'</VERSION>
            <USERIP>'.request()->ip().'</USERIP>
            <MCHNTCD>'.self::$merchantCode.'</MCHNTCD>
            <TYPE>'.self::$config['TYPE'].'</TYPE>
            <MCHNTORDERID>'.$fyParam['MCHNTORDERID'].'</MCHNTORDERID>
            <USERID>'.$userInfo['ID'].'</USERID>
            <ORDERID>'.$fyParam['ORDERID'].'</ORDERID>
            <BANKCARD>'.$userBankInfo['BankNo'].'</BANKCARD>
            <MOBILE>'.$userBankInfo['YMobile'].'</MOBILE>
            <VERCD>'.$postData['vsCode'].'</VERCD>
            <SIGNTP>'.self::$config['SIGNTP'].'</SIGNTP>
            <SIGN>'.$sign.'</SIGN>
            <SIGNPAY>'.$fyParam['SIGNPAY'].'</SIGNPAY>
        </REQUEST>';

        $APIFMS = CryptDes::encrypt_base64($STR, self::$secretKey);
        $param = [
            'MCHNTCD' => self::$merchantCode,
            'APIFMS' => $APIFMS,
        ];
        $result = $this->curlPost(self::$requestUrl['pay'], $param);
        $xml_result = CryptDes::decrypt_base64($result, self::$secretKey);
        $result = $this->xmlToArray($xml_result);
        if (isset($result['RESPONSECODE']) && $result['RESPONSECODE'] == '0000') {
            $this->resSuccess('下单成功', 000, $result);
        } else {
            Log::record('富友-商户下单-返回数据 解密前'.$result);
            Log::record('富友-商户下单-返回数据 解密后 '.$xml_result);
            $this->resError('下单失败');
        }
    }

    /**
     * 3.3 重发验证码接口.
     */
    public function messageAction()
    {
    }

    /**
     *  3.7 商户支持卡 Bin 查询接口
     *  接口说明：商户可通过此接口对此卡是否为协议支付－笔笔验证支持银行的卡进行查询。此接口仅通过传
     *  递卡号的卡 BIN（卡号前 6-12 位）对所归属银行进行判断。
     */
    public function checkBank()
    {
        $url = 'http://www-1.fuioupay.com:18670/mobile_pay/findPay/cardBinQuery.pay';
        $result = $this->curlPost($url);
    }

    /**
     * curl 请求
     *
     * @param url   $url       请求地址
     * @param array $postParam 请求参数
     */
    public function curlPost($url, $postParam = [])
    {
        $header = ['Content-Type: application/x-www-form-urlencoded;charset=UTF-8'];
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
        curl_setopt($curl, CURLOPT_POST, true);
        curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($postParam));
        $sResult = curl_exec($curl);
        curl_close($curl);

        return $sResult;
    }

    /**
     * 初始化支付配置.
     */
    public function initConfig()
    {
        $data = model('System')->getServerConfig('fuyou', true);
        if (!$data) {
            $this->resError('未配置富友支付');
        }

        $temp = [];
        foreach ($data as $k => $v) {
            $temp[$v['ParaName']] = $v['ParaValue'];
        }

        if (!$temp || !isset($temp['mchntCd']) || empty($temp['mchntCd'])) {
            $this->resError('未配置富友支付商户代码 mchntCd');
        } elseif (!$temp || !isset($temp['key']) || empty($temp['key'])) {
            $this->resError('未配置富友支付协议密钥 key');
        }

        self::$merchantCode = $temp['mchntCd'];
        self::$secretKey = $temp['key'];
    }

    /**
     * 返回错误信息.
     *
     * @param string $msg  错误信息
     * @param string $code 错误码
     * @param array 数据
     *
     * @return josn
     */
    public function resError($msg, $code = '-1', $data = [])
    {
        $temp = [
            'status' => !empty($code) ? $code : 0,
            'msg' => !empty($msg) ? $msg : 'error',
            'data' => !empty($data) ? $data : null,
        ];

        echo json_encode($temp, JSON_UNESCAPED_UNICODE);
        die;
    }

    /**
     * 返回成功信息.
     */
    public function resSuccess($msg, $code, $data = [])
    {
        $temp = [
            'status' => !empty($code) ? $code : 1,
            'msg' => !empty($msg) ? $msg : 'success',
            'data' => !empty($data) ? $data : null,
        ];

        echo json_encode($temp, JSON_UNESCAPED_UNICODE);
        die;
    }

    /**
     * 将XML转为array.
     *
     * @param string $xml xml数据
     * @param array
     */
    public function xmlToArray($xml)
    {
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);

        return $values;
    }
}
